/*
	Project:	CoreEngine
	Author:		Dino Bojadzhievski
	File:		Vector2

	Defines a two-dimensional vector.
	Non-generic, non-polymorphic.
	Extends nothing.

	All angles given in degrees.
	Does not define cross product (mathematically defined only for 3 and 7 dimensions).
*/

#pragma once

#include <math.h>
#include "../CoreTypes.h"
#include <assert.h>

namespace CoreMath
{
	struct Vector2
	{
		/* Data. */

		real i, j;

		/* Constructors. */

		Vector2() {}

		Vector2(real i, real j)
		{
			this->i = i;
			this->j = j;
		}

		Vector2(const Vector2& toCopy)
		{
			this->i = toCopy.i;
			this->j = toCopy.j;
		}

		/* Operators. */
		inline bool operator==(const Vector2& toCompare) const
		{
			return (this->i == toCompare.i) && (this->j == toCompare.j);
		}

		inline bool operator!=(const Vector2& toCompare) const
		{
			return !(this == &toCompare);
		}

		inline Vector2 operator=(const Vector2& toAssign)
		{
			this->i = toAssign.i;
			this->j = toAssign.j;
			return *this;
		}

		inline Vector2 operator-() const
		{
			return *this * -1;
		}

		inline Vector2 operator+(const Vector2& toAdd) const
		{
			return Vector2(this->i + toAdd.i, this->j + toAdd.j);
		}

		inline Vector2 operator-(const Vector2& toSubtract) const
		{
			return Vector2(this->i - toSubtract.i, this->j - toSubtract.j);
		}

		inline Vector2 operator*(const real multiplier) const
		{
			return Vector2(this->i * multiplier, this->j * multiplier);
		}

		inline Vector2 operator/(const real divisor) const
		{
			return Vector2(this->i / divisor, this->j / divisor);
		}

		inline Vector2 operator+=(const Vector2& toAdd)
		{
			*this = *this + toAdd;
			return *this;
		}

		inline Vector2 operator-=(const Vector2& toSubtract)
		{
			*this = *this - toSubtract;
			return *this;
		}

		inline Vector2 operator*=(const real multiplier)
		{
			*this = *this * multiplier;
			return *this;
		}

		inline Vector2 operator/=(const real divisor)
		{
			*this = *this / divisor;
			return *this;
		}

		/* Standard vector operations. */

		inline void Normalize(void)
		{
			const real vectMagnitude = this->Magnitude();
			
			if (!vectMagnitude)
				return;

			this->i /= vectMagnitude;
			this->j /= vectMagnitude;
		}

		inline static Vector2 Normalize(const Vector2& toNormalize)
		{
			real vectMagnitude = toNormalize.Magnitude();
			return vectMagnitude != 0 ? Vector2(toNormalize.i / vectMagnitude, toNormalize.j / vectMagnitude) : toNormalize;
		}

		inline real Magnitude() const
		{
			return sqrt(this -> SqrMagnitude());
		}

		inline real SqrMagnitude() const
		{
			return (this->i * this->i) + (this->j * this->j);
		}

		inline static real DotProduct(const Vector2& v1, const Vector2& v2)	// Sum of products of stuff.
		{
			real DotProduct = 0;
			DotProduct += (v1.i * v2.i);
			DotProduct += (v1.j * v2.j);

			return DotProduct;
		}

		inline static real AngleBetween(Vector2 v1, Vector2 v2)
		{
			/* 
				Optimization trick!
				Factors out the magnitudes.
			*/

			v1.Normalize();
			v2.Normalize();
			real product = DotProduct(v1, v2);
			return acos(product);
		}
	};
}